import {ShapeFlags} from "../shared/index.js";
import {getCurrentInstance} from "./component.js";
import {onMounted, onUpdated} from "./lifeCycle.js";

export const KeepAlive = {
    __isKeepAlive: true,
    setup(props, {slots}) {
        const keys = new Set(); // 存储组件的key
        const cache = new Map(); // 缓存的映射表
        const instance = getCurrentInstance();
        let {
            createElement,
            move,
            unmount: _unmount,
            patch,
        } = instance.ctx.renderer;
        const storageContainer = createElement("div");
        let pendingCacheKey = null;

        instance.ctx.activated = function (vnode, container) {
            move(vnode, container);
        };
        instance.ctx.deactivated = function (vnode) {
            // 在组件卸载过程中会执行此方法，将内容缓存起来，而不是走真正的卸载逻辑
            move(vnode, storageContainer);
        };

        function toCache() {
            cache.set(pendingCacheKey, instance.subTree); // 缓存的是keep-alive的插槽
        }

        onMounted(toCache);
        onUpdated(toCache);


        function unmount(vnode) {
            let flag = vnode.shapeFlag;
            if (flag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {
                flag -= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE;
            }
            if (flag & ShapeFlags.COMPONENT_KEPT_ALIVE) {
                flag -= ShapeFlags.COMPONENT_KEPT_ALIVE;
            }
            vnode.shapeFlag = flag;
            _unmount(vnode, instance);
        }

        function pruneCacheEntry(key) {
            unmount(cache.get(key));
            keys.delete(key);
            cache.delete(key);
        }

        return () => {
            const vnode = slots.default();

            const key = vnode.type;
            pendingCacheKey = key;
            const cacheVnode = cache.get(key); // 获取缓存的组件

            if (cacheVnode) {
                vnode.component = cacheVnode.component;
                vnode.shapeFlag |= ShapeFlags.COMPONENT_KEPT_ALIVE;
                keys.delete(key); // 将最新访问放到最后
            } else {
                keys.add(key);
                if (props.max && keys.size > props.max) {
                    // 缓存的个数超过了最大值
                    pruneCacheEntry(keys.values().next().value); // 删除第一个
                }
            }
            vnode.shapeFlag =
                vnode.shapeFlag | ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE;
            return vnode;
        };
    },
};

export const isKeepAlive = (vnode) => vnode.type.__isKeepAlive;
